<html>
<head>
<title>YUI DataTable Tests</title>
<link type="text/css" rel="stylesheet" href="../build/logger/assets/skins/sam/logger.css" />
<link type="text/css" rel="stylesheet" href="../build/yuitest/assets/testlogger.css" />
<link type="text/css" rel="stylesheet" href="../build/datatable/assets/skins/sam/datatable.css" />
<style type="text/css">
.yui-skin-sam .yui-log .yui-log-bd {height:60em;margin-top:2em;}
</style>

<script type="text/javascript" src="../build/yahoo/yahoo-min.js"></script>
<script type="text/javascript" src="../build/dom/dom-min.js"></script>
<script type="text/javascript" src="../build/event/event-min.js"></script>
<script type="text/javascript" src="../build/logger/logger-min.js"></script>
<script type="text/javascript" src="../build/yuitest/yuitest-beta.js"></script>
<script type="text/javascript" src="../build/element/element-beta-min.js"></script>
<script type="text/javascript" src="../build/datasource/datasource-beta-min.js"></script>
<script type="text/javascript" src="../build/datatable/datatable-beta.js"></script>

</head>
<body class="yui-skin-sam">
<h1>DataTable Tests</h1>
<p><input type="button" value="Run Tests" id="btnRun" disabled="true" /></p>

<script type="text/javascript">

(function() {

    var gCount = -1;

    var Dom=YAHOO.util.Dom,
        Assert=YAHOO.util.Assert,
        ObjectAssert=YAHOO.util.ObjectAssert,
        ArrayAssert=YAHOO.util.ArrayAssert,
        DateAssert=YAHOO.util.DateAssert,
        UserAction=YAHOO.util.UserAction,
        TestCase = YAHOO.tool.TestCase,
        TestLogger = YAHOO.tool.TestLogger,
        TestRunner = YAHOO.tool.TestRunner,
        TestSuite = YAHOO.tool.TestSuite,

        DataSource = YAHOO.util.DataSource,
        DataTable = YAHOO.widget.DataTable,
        ColumnSet = YAHOO.widget.ColumnSet,
        RecordSet = YAHOO.widget.RecordSet;

    var DataTableAssert = {
        areSameRow: function(elRow, oRecord, dt,  msg) {
            Assert.areSame("tr", elRow.tagName.toLowerCase(), "Expected a TR element: " + msg);
            Assert.areSame(elRow.yuiRecordId, oRecord.getId(), "Unexpected Record ID: " + msg);
            Assert.areSame(elRow.sectionRowIndex, dt.getTrIndex(oRecord), "Unexpected sectionRowIndex: " + msg);
        },
        
        areSameCell: function(elCell, oRecord, oColumn, dt, msg) {
            Assert.areSame("td", elCell.tagName.toLowerCase(), "Expected a TD element: " + msg);
            Assert.areSame(elCell.yuiCellIndex, oColumn.getKeyIndex(), "Unexpected yuiCellIndex: " + msg);
            Assert.areSame(elCell.yuiColumnKey, oColumn.getKey(), "Unexpected Column Key: " + msg);
            this.areSameRow(elCell.parentNode, oRecord, dt, msg);
        }
    };

    function DataTableTestCase(template) {
        DataTableTestCase.superclass.constructor.call(this, template);
    };
    YAHOO.lang.extend(DataTableTestCase, TestCase);

    DataTableTestCase.prototype.setUp = function() {
        this.container = document.createElement("div");
        this.container.id = "testDTContainer";
        document.body.appendChild(this.container);
        
        this.datasource = new YAHOO.util.DataSource(this.data, this.dsConfig);
    };

    DataTableTestCase.prototype.tearDown = function() {
        this.datatable.destroy();
        this.datatable = null;
        
        if (this.container != null) {
            YAHOO.util.Event.purgeElement(this.container, true);
            document.body.removeChild(this.container);
        }
        
        this.datasource = null;
    };

    DataTableTestCase.prototype.createInstance = function(oConfig) {
        this.datatable = new DataTable(this.container, this.columns, this.datasource, oConfig);
        gCount++;
        return this.datatable;
    };

    var dtBaseTemplate = {
        name: "DataTable Base Tests",
        
        data: [
            {a:"0a",b:"0b",c:"0c"},
            {a:"1a",b:"1b",c:"1c"},
            {a:"2a",b:"2b",c:"2c"},
            {a:"3a",b:"3b",c:"3c"}
        ],
            
        dsConfig: {
            responseType:YAHOO.util.DataSource.TYPE_JSARRAY,
            responseSchema:{fields:["a","b","c"]}
        },

        columns: [{key:"a"},{key:"b"},{key:"c"}],

        testConstruction: function() {
            var dt = this.createInstance();
            
            Assert.isObject(dt, "Failed to create DataTable instance");
            Assert.isInstanceOf(DataTable, dt, "Failed to create DataTable instance");
            Assert.isInstanceOf(ColumnSet, dt.getColumnSet(), "Failed to create ColumnSet instance");
            Assert.isInstanceOf(RecordSet, dt.getRecordSet(), "Failed to create RecordSet instance");
            Assert.areSame(this.data.length, dt.getRecordSet().getLength(), "Unexpected RecordSet length");
        }
    };
    
    /**
     *
     *
     * Tests various construction use cases.
     *
     *
     */
    var dtConstructionTemplate = YAHOO.lang.merge(dtBaseTemplate, {
        name: "DataTable Construction Tests",

        testNestedHeaders: function() {
            /* TODO */
            var dt = this.createInstance();
        },
        
        testMultipleInstances: function() {
            var multiple = 3; // Set how many instances (total) to create for this test case
            
            // Create first instance
            var dt = this.createInstance();
            var cs = dt._oColumnSet;
            var oColumn = cs.keys[0];

            // Create more instances
            for(var i=1; i<multiple; i++) {
                this["container"+i] = document.createElement("div");
                this["container"+i].id = "testDTContainer"+i;
                document.body.appendChild(this["container"+i]);

                this["datasource"+i] = new YAHOO.util.DataSource(this.data, this.dsConfig);
                
                this["dt"+i] = new YAHOO.widget.DataTable(this["container"+i], this.columns, this["datasource"+i]);
                this["cs"+i] = this["dt"+i].getColumnSet();
                gCount++;
            }
            
            // Test getColumn() on first instance
            var el = dt.getTheadEl().rows[0].cells[0];
            var oTestColumn = dt.getColumn(el);
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by el reference");

            oTestColumn = dt.getColumn(el.id);
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by DOM ID");

            oTestColumn = dt.getColumn(0);
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by key index");

            oTestColumn = cs.getColumn("a");
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by key (ColumnSet method)");

            oTestColumn = cs.getColumnById(oTestColumn.getId());
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by Column ID (ColumnSet method)");
            
            // Test getColumn() on other instances
            for(var i=1; i<multiple; i++) {
                oColumn = this["cs"+i].keys[0];
                
                el = this["dt"+i].getTheadEl().rows[0].cells[0];
                oTestColumn = this["dt"+i].getColumn(el);
                Assert.areSame(oColumn, oTestColumn, "Expected to get Column by el reference");

                oTestColumn = this["dt"+i].getColumn(el.id);
                Assert.areSame(oColumn, oTestColumn, "Expected to get Column by DOM ID");

                oTestColumn = this["dt"+i].getColumn(0);
                Assert.areSame(oColumn, oTestColumn, "Expected to get Column by key index");

                oTestColumn = this["cs"+i].getColumn("a");
                Assert.areSame(oColumn, oTestColumn, "Expected to get Column by key");

                oTestColumn = this["cs"+i].getColumnById(oTestColumn.getId());
                Assert.areSame(oColumn, oTestColumn, "Expected to get Column by Column ID");
            }

            // Destroy the other instances (first instance gets destroyed by the tearDown() function)
            for(var i=1; i<3; i++) {
                this["dt"+i].destroy();
                this["dt"+i] = null;

                if (this["container"+i] != null) {
                    YAHOO.util.Event.purgeElement(this["container"+i], true);
                    document.body.removeChild(this["container"+i]);
                }

                this.datasource = null;
            }
        }
    });
    var dtConstructionTest = new DataTableTestCase(dtConstructionTemplate)

    /**
     *
     *
     * Tests DOM element getters.
     *
     *
     */
    var dtDomAccessorsTemplate = YAHOO.lang.merge(dtBaseTemplate, {
        name: "DataTable DOM Accessors Tests",

        testGetTableEl: function() {
            var dt = this.createInstance();
            var elTable = dt.getTableEl();
            
            Assert.areSame("table", elTable.tagName.toLowerCase(), "Expected a TABLE element");
            Assert.areSame(dt.id+"-table", elTable.id, "Failed to generate correct TABLE DOM ID");
        },

        testGetMsgTbodyEl: function() {
            var dt = this.createInstance();
            var elTable = dt.getTableEl();
            var elTbody = dt.getMsgTbodyEl();
            
            Assert.areSame("tbody", elTbody.tagName.toLowerCase(), "Expected a TBODY element");
            //TODO: generate ID for tbody?
            //Assert.areSame(dt.id+"-tbody", elTbody.id, "Failed to generate correct TBODY DOM ID");
            Assert.areSame(elTable.tBodies[0], elTbody, "Expected to get first TBODY element of the TABLE");
        },

        testGetTbodyEl: function() {
            var dt = this.createInstance();
            var elTable = dt.getTableEl();
            var elTbody = dt.getTbodyEl();
            
            Assert.areSame("tbody", elTbody.tagName.toLowerCase(), "Expected a TBODY element");
            //TODO: generate ID for tbody?
            //Assert.areSame(dt.id+"-tbody", elTbody.id, "Failed to generate correct TBODY DOM ID");
            Assert.areSame(elTable.tBodies[1], elTbody, "Expected to get second TBODY element of the TABLE");
        },

        testGetFirstTrEl: function() {
            var dt = this.createInstance();
            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Expected row and Record to be in sync");
        },

        testGetLastTrEl: function() {
            var dt = this.createInstance();
            var elRow = dt.getLastTrEl();
            var oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            
            Assert.areSame(dt.id+"-bdrow3", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Expected row and Record to be in sync");
        },
        
        testGetTrEl: function() {
            var dt = this.createInstance();
            var elRow = dt.getTrEl(dt.id+"-bdrow0");
            var elTestTr = dt.getTbodyEl().rows[0];

            Assert.areSame(elTestTr, elRow, "By DOM ID: TR el mismatch");

            elRow = dt.getTrEl(dt.getTbodyEl().rows[0]);

            Assert.areSame(elTestTr, elRow, "By el ref: TR el mismatch");

            elRow = dt.getTrEl(0);

            Assert.areSame(elTestTr, elRow, "Page row index: TR el mismatch");

            elRow = dt.getTrEl(dt._oRecordSet._records[0]);

            Assert.areSame(elTestTr, elRow, "Record instance: TR el mismatch");
        },

        testGetsAfterDeleteRow: function() {
            var dt = this.createInstance();
            var oRecord = dt.getRecord(0);
            dt.deleteRow(0);
            var elTestRow = dt.getTrEl(oRecord);

            Assert.areSame(null, elTestRow, "Expected null TR el returned");

            var nTestIndex = dt.getTrIndex(oRecord);

            Assert.areSame(null, nTestIndex, "Expected null TR index returned");

            var oTestRecord = dt.getRecord(oRecord);

            Assert.areSame(null, oTestRecord, "Expected null Record returned");

            oTestRecord = dt.getRecordSet().getRecord(oRecord);

            Assert.areSame(null, oTestRecord, "Expected null Record returned (RecordSet method)");
        }
    });
    var dtDomAccessorsTest = new DataTableTestCase(dtDomAccessorsTemplate);

    /**
     *
     *
     * Tests RecordSet APIs.
     *
     *
     */
    var dtRecordSetTemplate = YAHOO.lang.merge(dtBaseTemplate, {
        name: "DataTable RecordSet Tests",

        testGetRecordSet: function() {
            var dt = this.createInstance();
            var rs = dt.getRecordSet();

            Assert.isInstanceOf(RecordSet, rs, "Expected a RecordSet");
        },
        
        testGetRecord: function() {
            var dt = this.createInstance();
            var rs = dt.getRecordSet();
            var oRecord = rs._records[3];
            var sRecordId = oRecord.getId();

            var el = dt.getTbodyEl().rows[3];
            var oTestRecord = dt.getRecord(el);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record by el reference");

            var el = dt.getTbodyEl().rows[3].cells[2];
            oTestRecord = dt.getRecord(el);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record by el reference child");

            el = Dom.get(dt.id+"-bdrow3");
            oTestRecord = dt.getRecord(el);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record by DOM ID");

            oTestRecord = dt.getRecord(3);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record by position index");

            oTestRecord = dt.getRecord(sRecordId);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record by Record ID");
            
            oTestRecord = dt.getRecord(oRecord);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record by Record instance");

            oTestRecord = rs.getRecord(3);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record by position index (RecordSet method)");

            oTestRecord = rs.getRecord(sRecordId);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record by Record ID (RecordSet method)");
            
            oTestRecord = rs.getRecord(oRecord);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record by Record instance (RecordSet method)");
        },
        
        testGetInvalidRecord: function() {
            var dt = this.createInstance();
            var rs = dt.getRecordSet();
            var oRecord = rs._records[3];
            dt.deleteRow(3);

            oTestRecord = dt.getRecord(oRecord);
            Assert.areSame(null, oTestRecord, "Expected not to get Record by invalid Record instance");

            oTestRecord = rs.getRecord(oRecord);
            Assert.areSame(null, oTestRecord, "Expected not to get Record by invalid Record instance (RecordSet method)");
        },

        testUpdateKey: function() {
            var dt = this.createInstance();
            var rs = dt.getRecordSet();
            var oTestRecord = rs._records[0];
            rs.updateKey(0, "b", "xxx");
            Assert.areSame("xxx", oTestRecord.getData("b"), "Failed to update key b of Record 0 by position index");

            rs.updateKey(oTestRecord, "b", "zzz");
            Assert.areSame("zzz", oTestRecord.getData("b"), "Failed to update key b of Record 0 by instance");

            rs.updateKey(oTestRecord.getId(), "b", "yyy");
            Assert.areSame("yyy", oTestRecord.getData("b"), "Failed to update key b of Record 0 by ID");
        }


        //TODO: More RecordSet APIs
    });
    var dtRecordSetTest = new DataTableTestCase(dtRecordSetTemplate);

    /**
     *
     *
     * Tests ColumnSet APIs.
     *
     *
     */
    var dtColumnSetTemplate = YAHOO.lang.merge(dtBaseTemplate, {
        name: "DataTable ColumnSet Tests",

        testGetColumnSet: function() {
            var dt = this.createInstance();
            var cs = dt.getColumnSet();

            Assert.isInstanceOf(ColumnSet, cs, "Expected a ColumnSet");
        },
        
        testGetColumn: function() {
            var dt = this.createInstance();
            var cs = dt.getColumnSet();
            var oColumn = cs.keys[0];
            var sColId = oColumn.getId();
            
            var el = dt.getTheadEl().rows[0].cells[0];
            var oTestColumn = dt.getColumn(el);
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by el reference");
            
            //TODO: get column by el reference child
            
            el = Dom.get(dt.id+"-col"+sColId);
            oTestColumn = dt.getColumn(el);
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by DOM ID");
            
            oTestColumn = dt.getColumn(0);
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by key index");

            oTestColumn = cs.getColumn("a");
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by key (ColumnSet method)");

            oTestColumn = cs.getColumnById(sColId);
            Assert.areSame(oColumn, oTestColumn, "Expected to get Column by Column ID (ColumnSet method)");
        }

        //TODO: More ColumnSet APIs
    });
    var dtColumnSetTest = new DataTableTestCase(dtColumnSetTemplate);

    /**
     *
     *
     * Tests row mutation APIs.
     *
     *
     */
    var dtRowMutationTemplate = YAHOO.lang.merge(dtBaseTemplate, {
        name: "DataTable Row Mutation Tests",
        testInsertRow: function() {
            var dt = this.createInstance();
            dt.addRow({a:"4a",b:"4b",c:"4c"}, 0);
            
            var oTestRecord = dt._oRecordSet._records[0];
            var elRow = dt.getFirstTrEl();
            Assert.areSame(dt.id+"-bdrow4", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Expected row and Record to be in sync");
        },
        
        testAppendRow: function() {
            var dt = this.createInstance();
            dt.addRow({a:"4a",b:"4b",c:"4c"});
            
            var oTestRecord = dt._oRecordSet._records[4];
            var elRow = dt.getLastTrEl();
            Assert.areSame(dt.id+"-bdrow4", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Expected row and Record to be in sync");
        },

        testUpdateRow: function() {
            var dt = this.createInstance();
            var newData = {a:"4a",b:"4b",c:"4c"};
            dt.updateRow(0, newData);
            
            var oData = dt.getRecord(0).getData();
            Assert.areSame(newData, oData, "Failed to update by Record index");

            newData = {a:"5a",b:"5b",c:"5c"};
            dt.updateRow(dt.getRecord(0), newData);

            oData = dt.getRecord(0).getData();
            Assert.areSame(newData, oData, "Failed to update by Record instance");
            
            newData = {a:"6a",b:"6b",c:"6c"};
            dt.updateRow(dt.id+"-bdrow"+0, newData);

            oData = dt.getRecord(0).getData();
            Assert.areSame(newData, oData, "Failed to update by TR el ID");

            newData = {a:"7a",b:"7b",c:"7c"};
            dt.updateRow(Dom.get(dt.id+"-bdrow"+0), newData);

            oData = dt.getRecord(0).getData();
            Assert.areSame(newData, oData, "Failed to update by TR el reference");
        },

        testUpdateInvalidRow: function() {
            var dt = this.createInstance();
            var oRecord = dt.getRecord(0);
            dt.deleteRow(0);
            var oData = {a:"4a", b:"4b", c:"4b"};
            dt.updateRow(oRecord, oData);

            var oTestRecords = dt.getRecordSet().getRecords();
            for(var i=0; i<oTestRecords.length; i++) {
                var oTestData = oTestRecords[i].getData();
                Assert.areNotSame(oData, oTestData, "Record "+i+"should not have updated");
            }
        },

        testDeleteFirstRow: function() {
            var dt = this.createInstance();
            dt.deleteRow(dt.getFirstTrEl());
            
            var oTestRecord = dt._oRecordSet._records[0];
            var elRow = dt.getFirstTrEl();
            Assert.areSame(dt.id+"-bdrow1", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Expected row and Record to be in sync");
        },
        
        testDeleteAppendThenInsert: function() {
            var dt = this.createInstance();
            dt.deleteRow(dt.getFirstTrEl());
            dt.addRow({a:"4a",b:"4b",c:"4c"});
            dt.addRow({a:"5a",b:"5b",c:"5c"},0);

            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow5", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Expected row and Record to be in sync");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow4", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Expected row and Record to be in sync");
        },

        testDeleteRows: function() {
            var dt = this.createInstance();
            dt.deleteRow(0);
            
            var nRecordsLength = dt.getRecordSet().getLength();
            var nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(3, nRecordsLength, "Expected 3 Records left");
            Assert.areSame(3, nTrElsLength, "Expected 3 TR els left");

            dt.deleteRow(0);
            
            nRecordsLength = dt.getRecordSet().getLength();
            nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(2, nRecordsLength, "Expected 2 Records left");
            Assert.areSame(2, nTrElsLength, "Expected 2 TR els left");

            dt.deleteRow(0);
            
            nRecordsLength = dt.getRecordSet().getLength();
            nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(1, nRecordsLength, "Expected 1 Records left");
            Assert.areSame(1, nTrElsLength, "Expected 1 TR els left");

            dt.deleteRow(0);
            
            nRecordsLength = dt.getRecordSet().getLength();
            nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(0, nRecordsLength, "Expected 0 Records left");
            Assert.areSame(0, nTrElsLength, "Expected 0 TR els left");
            Assert.areSame("", dt.getMsgTbodyEl().rows[0].cells[0].style.display, "Expected message displayed");
            Assert.areSame(true, Dom.hasClass(dt.getMsgTbodyEl().rows[0].cells[0], "yui-dt-empty"), "Expected empty message");
        },

        testDeleteRowsInReverse: function() {
            var dt = this.createInstance();
            dt.deleteRow(3);
            
            var nRecordsLength = dt.getRecordSet().getLength();
            var nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(3, nRecordsLength, "Expected 3 Records left");
            Assert.areSame(3, nTrElsLength, "Expected 3 TR els left");

            dt.deleteRow(2);
            
            nRecordsLength = dt.getRecordSet().getLength();
            nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(2, nRecordsLength, "Expected 2 Records left");
            Assert.areSame(2, nTrElsLength, "Expected 2 TR els left");

            dt.deleteRow(1);
            
            nRecordsLength = dt.getRecordSet().getLength();
            nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(1, nRecordsLength, "Expected 1 Records left");
            Assert.areSame(1, nTrElsLength, "Expected 1 TR els left");

            dt.deleteRow(0);
            
            nRecordsLength = dt.getRecordSet().getLength();
            nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(0, nRecordsLength, "Expected 0 Records left");
            Assert.areSame(0, nTrElsLength, "Expected 0 TR els left");
            Assert.areSame("", dt.getMsgTbodyEl().rows[0].cells[0].style.display, "Expected message displayed");
            Assert.areSame(true, Dom.hasClass(dt.getMsgTbodyEl().rows[0].cells[0], "yui-dt-empty"), "Expected empty message");
        },

        testDeleteThenInsertRows: function() {
            var dt = this.createInstance();
            dt.deleteRow(0);
            dt.deleteRow(0);
            dt.deleteRow(0);
            dt.deleteRow(0);
            dt.addRow({a:"4a",b:"4b",c:"4c"}, 0);
            
            var nRecordsLength = dt.getRecordSet().getLength();
            var nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(1, nRecordsLength, "Expected 1 Record");
            Assert.areSame(1, nTrElsLength, "Expected 1 TR el");
            
            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Insert 1: Row mismatch");

            dt.addRow({a:"5a",b:"5b",c:"5c"}, 0);
            
            nRecordsLength = dt.getRecordSet().getLength();
            nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(2, nRecordsLength, "Expected 2 Records");
            Assert.areSame(2, nTrElsLength, "Expected 2 TR els");
            
            elRow = dt.getFirstTrEl();
            oTestRecord = dt._oRecordSet._records[0];
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Insert 2: Row mismatch");

            dt.addRow({a:"6a",b:"6b",c:"6c"}, 0);
            
            nRecordsLength = dt.getRecordSet().getLength();
            nTrElsLength = dt.getTbodyEl().rows.length;
            Assert.areSame(3, nRecordsLength, "Expected 3 Records");
            Assert.areSame(3, nTrElsLength, "Expected 3 TR els");
            
            elRow = dt.getFirstTrEl();
            oTestRecord = dt.getRecord(dt.getFirstTrEl());
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Insert 3: Row mismatch");
        },

        testDeleteInsertThenSortRows: function() {
            var dt = this.createInstance();
            dt.deleteRow(0);
            dt.deleteRow(0);
            dt.deleteRow(0);
            dt.deleteRow(0);
            dt.addRow({a:"4a",b:"4b",c:"4c"}, 0);
            dt.addRow({a:"5a",b:"5b",c:"5c"}, 0);
            dt.addRow({a:"6a",b:"6b",c:"6c"}, 0);
            dt.sortColumn(dt.getColumn(0));

            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow6", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Expected row and Record to be in sync");
        }
    });
    var dtRowMutationTest = new DataTableTestCase(dtRowMutationTemplate);

    /**
     *
     *
     * Tests sorting APIs.
     *
     *
     */
    var dtSortingTemplate = YAHOO.lang.merge(dtBaseTemplate, {
        name: "DataTable Sorting Tests",
        
        data: [
            {a:0,b:"zero"},
            {a:1,b:"one"},
            {a:2,b:"two"},
            {a:3,b:"three"}
        ],
            
        dsConfig: {
            responseType:YAHOO.util.DataSource.TYPE_JSARRAY,
            responseSchema:{fields:["a","b"]}
        },

        columns: [
            {key:"a",label:"numbers",sortable:true},
            {key:"b",label:"strings",sortable:true}
        ],

        testSortByElementClick: function() {
            var dt = this.createInstance();
            var oColumn = dt.getColumn(1);
            var el = dt.getThEl(oColumn);
            UserAction.click(el);
            
            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Click TH: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Click TH: Row mismatch");

            el = Dom.get(dt.id+"-container"+oColumn.getId());
            UserAction.click(el);
            
            elRow = dt.getFirstTrEl();
            oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame("zero", dt.getRecord(dt.getFirstTrEl()).getData("b"), "Click container: Unexpected data");
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Click container: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Click container: Row mismatch");
            
            el = Dom.get(dt.id+"-label"+oColumn.getId());
            UserAction.click(el);
            
            elRow = dt.getFirstTrEl();
            oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame("one", dt.getRecord(dt.getFirstTrEl()).getData("b"), "Click label: Unexpected data");
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Click label: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Click label: Row mismatch");
        },

        testSortNumber: function() {
            var dt = this.createInstance();
            var oColumn = dt.getColumn(0);
            dt.sortColumn(oColumn);
            
            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Top asc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Top asc: Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow3", elRow.id, "Bottom asc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Bottom asc: Row mismatch");

            dt.sortColumn(oColumn);
            
            elRow = dt.getFirstTrEl();
            oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Top desc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Top desc: Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow3", elRow.id, "Bottom desc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Bottom desc: Row mismatch");
        },

        testSortString: function() {
            var dt = this.createInstance();
            var oColumn = dt.getColumn(1);
            dt.sortColumn(oColumn);

            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Top asc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Top asc: Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow3", elRow.id, "Bottom asc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Bottom asc: Row mismatch");

            dt.sortColumn(oColumn);
            
            elRow = dt.getFirstTrEl();
            oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Top desc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Top desc: Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow3", elRow.id, "Bottom desc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Bottom desc: Row mismatch");
        },

        testInsertThenSort: function() {
            var dt = this.createInstance();
            dt.addRow({a:4,b:"four"}, 0)
            dt.sortColumn(dt.getColumn(1));
            
            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow4", elRow.id, "Top asc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Top asc: Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow3", elRow.id, "Bottom asc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Bottom asc: Row mismatch");
            
            dt.sortColumn(dt.getColumn(1));

            elRow = dt.getFirstTrEl();
            oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow4", elRow.id, "Top desc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Top desc: Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow3", elRow.id, "Bottom desc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Bottom desc: Row mismatch");
        },
        
        testSortThenAppend: function() {
            var dt = this.createInstance();
            dt.sortColumn(dt.getColumn(1));
            dt.addRow({a:4,b:"four"});

            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Top asc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Top asc: Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow4", elRow.id, "Bottom asc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Bottom asc: Row mismatch");

            dt.sortColumn(dt.getColumn(1));
            
            elRow = dt.getFirstTrEl();
            oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Top asc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Top desc: Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow4", elRow.id, "Bottom desc: Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Bottom desc: Row mismatch");
        },
        
        testDeleteAppendInsertThenSort: function() {
            var dt = this.createInstance();
            dt.deleteRow(dt.getFirstTrEl());
            dt.addRow({a:4,b:"four"});
            dt.addRow({a:5,b:"five"},0);
            dt.sortColumn(dt.getColumn(1));

            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(dt.id+"-bdrow5", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow4", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Row mismatch");
        }
    });
    var dtSortingTest = new DataTableTestCase(dtSortingTemplate);
    
    /**
     *
     *
     * Tests row selection APIs.
     *
     *
     */
    var dtRowSelectionTemplate = YAHOO.lang.merge(dtBaseTemplate, {
        name: "DataTable Row Selection Tests",

        testSelectUnselectByEl: function() {
            var dt = this.createInstance();
            var elRow = dt.getFirstTrEl();
            dt.selectRow(elRow);
            
            var aSelectedRows = dt.getSelectedRows();
            Assert.areSame(true, YAHOO.util.Dom.hasClass(elRow, "yui-dt-selected"), "Failed to apply CSS");
            ArrayAssert.contains(elRow.yuiRecordId, aSelectedRows, "Failed to select first row");
            
            dt.unselectRow(elRow);
            
            aSelectedRows = dt.getSelectedRows();
            Assert.areSame(false, YAHOO.util.Dom.hasClass(elRow, "yui-dt-selected"), "Failed to remove CSS");
            ArrayAssert.doesNotContain(elRow.yuiRecordId, aSelectedRows, "Failed to unselect first row");

        },
        
        testSelectThenInsert: function() {
            var dt = this.createInstance();
            var elRow = dt.getFirstTrEl();
            dt.selectRow(elRow);
            dt.addRow({a:"4a",b:"4b",c:"4c"}, 0);
            
            var aSelectedRows = dt.getSelectedRows();
            var elTestRow = dt.getTbodyEl().rows[1];
            Assert.areSame(true, YAHOO.util.Dom.hasClass(elTestRow, "yui-dt-selected"), "Failed to apply CSS");
            ArrayAssert.contains(elTestRow.yuiRecordId, aSelectedRows, "Second row should be selected");

            elTestRow = dt.getTbodyEl().rows[0];
            Assert.areNotSame(true, YAHOO.util.Dom.hasClass(elTestRow, "yui-dt-selected"), "Unexpected CSS");
            ArrayAssert.doesNotContain(elTestRow.yuiRecordId, aSelectedRows, "First row should not be selected");
        },
        
        testSingleSelect: function() {
            var oConfig = {
                selectionMode:"single"
            }
            var dt = this.createInstance(oConfig);
            dt.subscribe("rowClickEvent",dt.onEventSelectRow,dt);
            var el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el);
            
            var aSelectedRows = dt.getSelectedRows();
            var aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            var elTestRow = dt.getTbodyEl().rows[0];
            ArrayAssert.itemsAreSame([elTestRow.yuiRecordId], aSelectedRows, "Expected only first row selected");
            ArrayAssert.itemsAreSame([el], aSelectedEls, "Expected only first TR el selected");

            el = Dom.get(dt.id+"-bdrow1");
            UserAction.click(el);
            el = Dom.get(dt.id+"-bdrow2");
            UserAction.click(el);
            el = Dom.get(dt.id+"-bdrow3");
            UserAction.click(el);
            
            aSelectedRows = dt.getSelectedRows();
            aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            var elTestRow = dt.getTbodyEl().rows[3];
            ArrayAssert.itemsAreSame([elTestRow.yuiRecordId], aSelectedRows, "Expected only fourth row selected");
            ArrayAssert.itemsAreSame([el], aSelectedEls, "Expected only fourth TR el selected");
        },
        
        testShiftSelect: function() {
            var dt = this.createInstance();
            dt.subscribe("rowClickEvent",dt.onEventSelectRow,dt);
            var el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el);
            el = Dom.get(dt.id+"-bdrow3");
            UserAction.click(el, {"shiftKey":true});
            
            var aSelectedRows = dt.getSelectedRows();
            var aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            var aTestRecordIds = [
                dt._oRecordSet._records[0].getId(),
                dt._oRecordSet._records[1].getId(),
                dt._oRecordSet._records[2].getId(),
                dt._oRecordSet._records[3].getId()
            ];
            var aTestTrEls = [
                dt.getTbodyEl().rows[0],
                dt.getTbodyEl().rows[1],
                dt.getTbodyEl().rows[2],
                dt.getTbodyEl().rows[3]
            ];
            ArrayAssert.itemsAreSame(aTestRecordIds, aSelectedRows, "Expected four rows selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Expected four TR els selected");

            el = Dom.get(dt.id+"-bdrow2");
            UserAction.click(el);
            
            aSelectedRows = dt.getSelectedRows();
            aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            aTestRecordIds = [
                dt._oRecordSet._records[2].getId()
            ];
            aTestTrEls = [
                dt.getTbodyEl().rows[2]
            ];
            ArrayAssert.itemsAreSame(aTestRecordIds, aSelectedRows, "Expected only third row selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Expected only third TR el selected");

            el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el, {"shiftKey":true});
            
            aSelectedRows = dt.getSelectedRows();
            aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            aTestRecordIds = [
                dt._oRecordSet._records[2].getId(),
                dt._oRecordSet._records[1].getId(),
                dt._oRecordSet._records[0].getId()
            ];
            aTestTrEls = [
                dt.getTbodyEl().rows[0],
                dt.getTbodyEl().rows[1],
                dt.getTbodyEl().rows[2]
            ];
            ArrayAssert.itemsAreSame(aTestRecordIds, aSelectedRows, "Expected three rows selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Expected three TR els selected");
        },
        
        testUnselectAllRows: function() {
            var dt = this.createInstance();
            dt.subscribe("rowClickEvent",dt.onEventSelectRow,dt);
            var el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el);
            el = Dom.get(dt.id+"-bdrow3");
            UserAction.click(el, {"shiftKey":true});
            dt.unselectAllRows();

            var aSelectedRows = dt.getSelectedRows();
            var aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            var aTestRecordIds = [];
            var aTestTrEls = [];
            ArrayAssert.itemsAreSame(aTestRecordIds, aSelectedRows, "Shift-select: Expected no rows selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Shift-select: Expected no TR els selected");

            el = Dom.get(dt.id+"-bdrow1");
            UserAction.click(el);
            el = Dom.get(dt.id+"-bdrow3");
            UserAction.click(el, {"ctrlKey":true});
            dt.unselectAllRows();

            aSelectedRows = dt.getSelectedRows();
            aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            ArrayAssert.itemsAreSame(aTestRecordIds, aSelectedRows, "Ctrl-select: Expected no rows selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Ctrl-select: Expected no rows selected");
        },
        
        testAppendX3ThenDeleteSingleSelectedFromTop: function() {
            var i;
            var dt = this.createInstance({selectionMode:"single"});
            dt.subscribe("rowClickEvent",dt.onEventSelectRow,dt);
            dt.addRow({a:"4a",b:"4b",c:"4c"});
            dt.addRow({a:"5a",b:"5b",c:"5c"});
            var el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el);
            var rows = dt.getSelectedRows();
            for(i=0; i<rows.length; i++) {
                var row = rows[i];
                //TODO: Support passing in Record ID to dt.getRecordIndex and rs.getRecordIndex
                dt.deleteRow(dt.getRecordIndex(dt.getRecord(row)));
            }
            
            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(5, dt.getRecordSet().getLength(), "Expected 5 Records");
            Assert.areSame(5, dt.getTbodyEl().rows.length, "Expected 5 TR els");
            Assert.areSame(dt.id+"-bdrow1", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Row mismatch");

            el = Dom.get(dt.id+"-bdrow1");
            UserAction.click(el);
            rows = dt.getSelectedRows();
            for(i=0; i<rows.length; i++) {
                var row = rows[i];
                //TODO: Support passing in Record ID to dt.getRecordIndex and rs.getRecordIndex
                dt.deleteRow(dt.getRecordIndex(dt.getRecord(row)));
            }
            
            elRow = dt.getFirstTrEl();
            oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(4, dt.getRecordSet().getLength(), "Expected 4 Records");
            Assert.areSame(4, dt.getTbodyEl().rows.length, "Expected 4 TR els");
            Assert.areSame(dt.id+"-bdrow2", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Row mismatch");
        }
    });
    var dtRowSelectionTest = new DataTableTestCase(dtRowSelectionTemplate);

    /**
     *
     *
     * Tests cell selection APIs.
     *
     *
     */
    var dtCellSelectionTemplate = YAHOO.lang.merge(dtBaseTemplate, {
        name: "DataTable Row Selection Tests"
    });
    var dtCellSelectionTest = new DataTableTestCase(dtCellSelectionTemplate);
    
    /**
     *
     *
     * Tests pagination APIs.
     *
     *
     */
    var dtPaginationTemplate = YAHOO.lang.merge(dtBaseTemplate, {
        name: "DataTable Pagination Tests",
        
        data: [
            {a:0},{a:1},{a:2},{a:3},{a:4},
            {a:5},{a:6},{a:7},{a:8},{a:9},
            {a:10},{a:11},{a:12},{a:13},{a:14},
            {a:15},{a:16},{a:17},{a:18},{a:19},
            {a:20},{a:21}
        ],

        dsConfig: {
            responseType:YAHOO.util.DataSource.TYPE_JSARRAY,
            responseSchema:{fields:["a"]}
        },

        columns: [{key:"a", sortable:true}],

        testPagination: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5}
            }
            var dt = this.createInstance(oConfig);
            
            Assert.areSame(5, dt.get("paginator").totalPages, "Expected 5 pages");
        },

        testPageThenSort: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5},
                sortedBy: {key:"a"}
            }
            var dt = this.createInstance(oConfig);
            dt.showPage(2);
            dt.sortColumn(dt.getColumn("a"));
            
            var elRow = dt.getFirstTrEl();
            var oTestRecord = dt._oRecordSet._records[0];
            Assert.areSame(1, dt.get("paginator").currentPage, "Expected to be on page 1");
            Assert.areSame(dt.id+"-bdrow0", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Row mismatch");

            elRow = dt.getLastTrEl();
            oTestRecord = dt._oRecordSet._records[elRow.sectionRowIndex];
            Assert.areSame(dt.id+"-bdrow4", elRow.id, "Unexpected DOM ID");
            DataTableAssert.areSameRow(elRow, oTestRecord, dt, "Row mismatch");
        },

        testDeleteRowsCurrentPage: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5}
            }
            var dt = this.createInstance(oConfig);
            dt.deleteRows(0,2);
            // Workaround bug 1391828
            dt.refreshView();
            
            Assert.areSame(4, dt.get("paginator").totalPages, "Expected 4 pages");
        },
        
         testDeleteRowsDifferentPage: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5}
            }
            var dt = this.createInstance(oConfig);
            dt.showPage(5);
            dt.deleteRows(0,2);
            // Workaround bug 1391828
            dt.refreshView();
            
            Assert.areSame(4, dt.get("paginator").totalPages, "Expected 4 pages");
            Assert.areSame(4, dt.get("paginator").currentPage, "Expected to be on page 4");
        },
        
        testSingleSelectAcrossPages: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5},
                selectionMode:"single"
            }
            var dt = this.createInstance(oConfig);
            dt.subscribe("rowClickEvent",dt.onEventSelectRow,dt);
            var el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el);
            dt.showPage(5);
            // Workaround bug 1391828
            dt.refreshView();
            el = Dom.get(dt.id+"-bdrow1");
            UserAction.click(el);
            
            var aSelectedRows = dt.getSelectedRows();
            var aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            var aTestRecords = [
                dt._oRecordSet._records[21].getId()
            ];
            var aTestTrEls = [
                dt.getTbodyEl().rows[1]
            ];
            ArrayAssert.itemsAreSame(aTestRecords, aSelectedRows, "Expected only second row of last page (Record index 21) selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Expected only second TR el selected");
        },
        
        testSingleSelectAcrossPagesAfterSort: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5},
                selectionMode:"single",
                sortedBy: {key:"a"}
            }
            var dt = this.createInstance(oConfig);
            dt.subscribe("rowClickEvent",dt.onEventSelectRow,dt);
            dt.showPage(4);
            var el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el);
            // Workaround bug 1391828
            dt.refreshView();
            dt.sortColumn(dt.getColumn(0));
            el = Dom.get(dt.id+"-bdrow4");
            UserAction.click(el);
            
            var aSelectedRows = dt.getSelectedRows();
            var aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            var aTestRecords = [
                dt._oRecordSet._records[4].getId()
            ];
            var aTestTrEls = [
                dt.getTbodyEl().rows[4]
            ];
            ArrayAssert.itemsAreSame(aTestRecords, aSelectedRows, "Expected only last row of first page (Record index 4) selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Expected only last TR el selected");
            
            dt.showPage(3);
            el = Dom.get(dt.id+"-bdrow2");
            UserAction.click(el);
            
            aSelectedRows = dt.getSelectedRows();
            aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            aTestRecords = [
                dt._oRecordSet._records[12].getId()
            ];
            aTestTrEls = [
                dt.getTbodyEl().rows[2]
            ];
            ArrayAssert.itemsAreSame(aTestRecords, aSelectedRows, "Expected only third row of third page (Record index 12) selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Expected only third TR el selected");
        },

        testShiftSelectAcrossPages: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5},
                selectionMode:"standard"
            }
            var dt = this.createInstance(oConfig);
            dt.subscribe("rowClickEvent",dt.onEventSelectRow,dt);
            var el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el);
            dt.showPage(2);
            el = Dom.get(dt.id+"-bdrow1");
            UserAction.click(el, {"shiftKey":true});
            
            var aSelectedRows = dt.getSelectedRows();
            var aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            var aTestRecords = [
                dt._oRecordSet._records[0].getId(),
                dt._oRecordSet._records[1].getId(),
                dt._oRecordSet._records[2].getId(),
                dt._oRecordSet._records[3].getId(),
                dt._oRecordSet._records[4].getId(),
                dt._oRecordSet._records[5].getId(),
                dt._oRecordSet._records[6].getId()
            ];
            var aTestTrEls = [
                dt.getTbodyEl().rows[0],
                dt.getTbodyEl().rows[1]
            ];
            ArrayAssert.itemsAreSame(aTestRecords, aSelectedRows, "Expected seven rows across two pages selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Expected first two TR els selected");

            el = Dom.get(dt.id+"-bdrow2");
            UserAction.click(el);
            
            aSelectedRows = dt.getSelectedRows();
            aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            aTestRecords = [
                dt._oRecordSet._records[7].getId()
            ];
            aTestTrEls = [
                dt.getTbodyEl().rows[2]
            ];
            ArrayAssert.itemsAreSame(aTestRecords, aSelectedRows, "Expected only third row of second page selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Expected only third TR el selected");
        },

        testUnselectAllRowsAcrossPages: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5},
                selectionMode:"standard"
            }
            var dt = this.createInstance(oConfig);
            dt.subscribe("rowClickEvent",dt.onEventSelectRow,dt);
            var el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el);
            dt.showPage(2);
            el = Dom.get(dt.id+"-bdrow1");
            UserAction.click(el, {"shiftKey":true});
            dt.unselectAllRows();

            var aSelectedRows = dt.getSelectedRows();
            var aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            var aTestRecords = [];
            var aTestTrEls = [];
            ArrayAssert.itemsAreSame(aTestRecords, aSelectedRows, "Shift-select: Expected no rows on any page selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Shift-select: Expected no TR els selected");

            el = Dom.get(dt.id+"-bdrow2");
            UserAction.click(el);
            el = Dom.get(dt.id+"-bdrow4");
            UserAction.click(el, {"ctrlKey":true});
            dt.showPage(3);
            el = Dom.get(dt.id+"-bdrow3");
            UserAction.click(el, {"ctrlKey":true});
            el = Dom.get(dt.id+"-bdrow4");
            UserAction.click(el, {"ctrlKey":true});
            dt.unselectAllRows();

            aSelectedRows = dt.getSelectedRows();
            aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            ArrayAssert.itemsAreSame(aTestRecords, aSelectedRows, "Ctrl-select: Expected no rows on any page selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Ctrl-select: Expected no TR els selected");
        },


        testSingleSelectAcrossRowsPerPage: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5},
                selectionMode:"single"
            }
            var dt = this.createInstance(oConfig);
            dt.subscribe("rowClickEvent",dt.onEventSelectRow,dt);
            var el = Dom.get(dt.id+"-bdrow0");
            UserAction.click(el);
            dt.showPage(2);
            el = Dom.get(dt.id+"-bdrow2");
            UserAction.click(el);
            dt.updatePaginator({rowsPerPage:10, currentPage:1});
            dt.refreshView();
            
            var aSelectedRows = dt.getSelectedRows();
            var aSelectedEls = Dom.getElementsByClassName("yui-dt-selected", "*", dt.getTbodyEl());
            var aTestRecords = [
                dt._oRecordSet._records[7].getId()
            ];
            var aTestTrEls = [
                dt.getTbodyEl().rows[7]
            ];
            ArrayAssert.itemsAreSame(aTestRecords, aSelectedRows, "Expected only one row selected");
            ArrayAssert.itemsAreSame(aTestTrEls, aSelectedEls, "Expected seventh TR el selected");
        },
        
        testGetRecordAcrossPages: function() {
            var oConfig = {
                paginated:true,
                paginator: {rowsPerPage:5},
                selectionMode:"single"
            }
            var dt = this.createInstance(oConfig);
            dt.showPage(4);

            // Get Record on this page
            var rs = dt.getRecordSet();
            var oRecord = rs._records[16];
            var sRecordId = oRecord.getId();

            var el = dt.getTbodyEl().rows[1];
            var oTestRecord = dt.getRecord(el);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record 16 by el reference");

            oTestRecord = dt.getRecord(16);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record 16 by position index");

            oTestRecord = dt.getRecord(sRecordId);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record 16 by Record ID");

            // Get Record on a different page
            oRecord = rs._records[1];
            sRecordId = oRecord.getId();
            oTestRecord = dt.getRecord(el);
            Assert.areNotSame(oRecord, oTestRecord, "Record for row 1 on this page should NOT be Record index 1");

            oTestRecord = dt.getRecord(1);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record 1 by position index");

            oTestRecord = dt.getRecord(sRecordId);
            Assert.areSame(oRecord, oTestRecord, "Expected to get Record 1 by Record ID");
        }
    });
    var dtPaginationTest = new DataTableTestCase(dtPaginationTemplate);

    YAHOO.util.Event.addListener(window, "load", function() {
        var logger = new TestLogger();
        
        var datatablesuite = new TestSuite("DataTable Test Suite");
        datatablesuite.add(dtConstructionTest);
        datatablesuite.add(dtDomAccessorsTest);
        datatablesuite.add(dtRecordSetTest);
        datatablesuite.add(dtColumnSetTest);
        datatablesuite.add(dtRowMutationTest);
        datatablesuite.add(dtSortingTest);
        datatablesuite.add(dtRowSelectionTest);
        datatablesuite.add(dtCellSelectionTest);
        datatablesuite.add(dtPaginationTest);
        
        TestRunner.add(datatablesuite);

        YAHOO.util.Event.addListener("btnRun", "click", function(){TestRunner.run();});
        YAHOO.util.Dom.get("btnRun").disabled = false;

        if (parent && parent != window) {
            YAHOO.tool.TestManager.load();
        }
    });
})();

</script>
</body>
</html>
